package org.systemsbiology.rface.hadoop.math;

import org.apache.commons.math.stat.clustering.Clusterable;
import org.apache.hadoop.io.WritableComparable;
import org.systemsbiology.util.KahanSummation;
import org.systemsbiology.util.Summator;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Collection;

/**
 * Created by IntelliJ IDEA.
 * User: anorberg
 * Date: 10/6/11
 * Time: 11:58 AM
 * To change this template use File | Settings | File Templates.
 */
public class ClusterableDouble1D implements Clusterable<ClusterableDouble1D>, WritableComparable<ClusterableDouble1D>{
    private double value;
    public ClusterableDouble1D(double d){
        value = d;
    }
    public ClusterableDouble1D(){
        value = Double.NaN;
    }
    public double getValue(){
        return value;
    }
    public String toString(){
        return "1D point: " + String.valueOf(value);
    }
    public double distanceFrom(ClusterableDouble1D other){
        return Math.abs(value - other.value);
    }

    public ClusterableDouble1D centroidOf(Collection<ClusterableDouble1D> elements){
        Summator total = new KahanSummation();
        int n = 0;
        for(ClusterableDouble1D point : elements){
            total.add(point.value);
            ++n;
        }
        return new ClusterableDouble1D(total.total() / n); //will divide 0 by 0 if no points, yielding NaN
    }

    public void write(DataOutput dout) throws IOException{
        dout.writeDouble(value);
    }

    public void readFields(DataInput din) throws IOException{
        value = din.readDouble();
    }

    public int compareTo(ClusterableDouble1D other){
        return Double.compare(value, other.value);
    }
    
    public boolean equals(Object o){
    	if(o == null) return false;
    	if(! o.getClass().equals(getClass())) return false;
    	return value == ((ClusterableDouble1D)o).value;
    }
    
    public int hashCode(){
    	return ~Double.valueOf(value).hashCode();
    }
}
